#include "stdafx.h"
#include "FileManager.h"

CxFileManager::CxFileManager()
{
}

CxFileManager::~CxFileManager()
{}

HRESULT CxFileManager::RegisterSymbolPath(BSTR bsSymbol, BSTR bsPath, INT nPriority)
{
    CString strSymbol = bsSymbol;
    strSymbol.MakeLower();

    if (strSymbol.GetLength() <= 1)
    {
        ATLASSERT(!L"symbol's length must greater than 1");
        return E_FAIL;
    }

    CString strPath = bsPath;
    strPath.MakeLower();
    strPath.Replace(L"\\", L"/");

    SYMBOLSIT iter = m_mapSymbols.find(bsSymbol);
    if (iter == m_mapSymbols.end())
    {
        PATHS paths;
        paths.insert(std::make_pair(nPriority, strPath));
        m_mapSymbols.insert(std::make_pair(strSymbol, paths));
    }
    else
    {
        (iter->second).insert(std::make_pair(nPriority, bsPath));
    }

    return S_OK;
}

HRESULT CxFileManager::UnregisterSymbolPath(BSTR bsSymbol, INT nPriority)
{
    CString strSymbol = bsSymbol;
    strSymbol.MakeLower();

    HRESULT hRet = E_FAIL;

    SYMBOLSIT iter = m_mapSymbols.find(strSymbol);
    if (iter != m_mapSymbols.end())
    {
        PATHSIT it_path = (iter->second).find(nPriority);
        if (it_path != (iter->second).end())
        {
            (iter->second).erase(it_path);
            hRet = S_OK;
        }
    }

    return hRet;
}

HRESULT CxFileManager::GetBuffer(BSTR bsFile, IxBuffer** ppBuffer)
{
    if (!ppBuffer)
    {
        return E_POINTER;
    }

    *ppBuffer = NULL;

    CString strFile = bsFile;
    strFile.MakeLower();
    strFile.Replace(L"\\", L"/");

    if (_is_absolute_path(strFile) || _is_relative_path(strFile))
    {
        return _get_buffer_from_disk(strFile, ppBuffer);
    }
    else if (_is_symbol_path(strFile))
    {
        return _get_buffer_from_pool(strFile, ppBuffer);
    }

    ATLASSERT(!L"the path is not valid!!!");

    return E_FAIL;
}

HRESULT CxFileManager::_get_buffer_from_disk(const CString& strFile, IxBuffer** ppBuffer)
{
    if (!ppBuffer)
    {
        return E_POINTER;
    }

    *ppBuffer = NULL;

    HRESULT hRet = E_FAIL;

    if (_is_file_exist(strFile))
    {
        HANDLE hFile = ::CreateFile(strFile, FILE_READ_DATA, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
        if (INVALID_HANDLE_VALUE != hFile)
        {
            DWORD dwLenHigh = 0;
            DWORD dwLen = ::GetFileSize(hFile, &dwLenHigh);
            if (0 != dwLenHigh)
            {
                ATLASSERT(!L"the file is too big!!!");
            }
            else
            {
                CComPtr<IxBuffer> spBuffer;
                ::xCommon::CreateObjectByIID(__uuidof(IxBuffer), (void**)&spBuffer);
                if (spBuffer)
                {
                    LPBYTE pbyBuffer = NULL;
                    spBuffer->Resize((UINT)dwLen, &pbyBuffer);
                    if (pbyBuffer)
                    {
                        DWORD dwReadLen = 0;
                        ::ReadFile(hFile, pbyBuffer, dwLen, &dwReadLen, NULL);
                        if (dwReadLen == dwLen)
                        {
                            hRet = spBuffer->QueryInterface(__uuidof(IxBuffer), (void**)ppBuffer);
                        }
                    }
                }
            }
            ::CloseHandle(hFile);
        }
        hRet = S_OK;
    }

    return hRet;
}

HRESULT CxFileManager::_get_buffer_from_pool(const CString& strFile, IxBuffer** ppBuffer)
{
    if (!ppBuffer)
    {
        return E_POINTER;
    }

    *ppBuffer = NULL;

    HRESULT hRet = E_FAIL;

    INT iPos = strFile.Find(_T(":\\"));
    if (-1 == iPos)
    {
        iPos = strFile.Find(_T(":/"));
    }

    CString strSymbol = strFile.Left(iPos);

    SYMBOLSIT it_symbol = m_mapSymbols.find(strSymbol);
    if (it_symbol != m_mapSymbols.end())
    {
        PATHS& paths = it_symbol->second;

        for (PATHSIT it_path = paths.begin(); it_path != paths.end(); ++it_path)
        {
            CString& strPath = it_path->second;
            if (_is_zip_file(strPath))
            {
                hRet = _get_buffer_from_zip(strPath, strFile, ppBuffer);
            }
            else
            {
                CString strDestPath = strPath + strFile.Right(strFile.GetLength() - iPos - 1);
                hRet = _get_buffer_from_disk(strDestPath, ppBuffer);
            }

            if (SUCCEEDED(hRet) && *ppBuffer)
            {
                break;
            }
        }
    }

    return hRet;
}

HRESULT CxFileManager::_get_buffer_from_zip(const CString& strZipFile, const CString& strFile, IxBuffer** ppBuffer)
{
    // to do ...
    ATLASSERT(!L"Not implement!!!");
    return E_FAIL;
}

bool CxFileManager::_is_file_exist(const CString& bsFile)
{
    bool bFind = false;

    WIN32_FIND_DATA tagData = {0};
    HANDLE hFind = ::FindFirstFile(bsFile, &tagData);

    if (INVALID_HANDLE_VALUE != hFind)
    {
        ::FindClose(hFind);
        bFind = true;
    }

    return bFind;
}